//
// Created by LiuYou on 2021/6/28.
//

#include <cstdlib>
#include <memory>
#include <cstring>
#include <unistd.h>


#define LEFT            30000000
#define RIGHT           30000200
#define THR_NUM         4


static int num = 0;
static pthread_mutex_t mutexNum = PTHREAD_MUTEX_INITIALIZER;


static void* thr_prime(void* pVoid);


/**
 * @brief 池的写法重构之前的线程实例。
 *
 * 任务池
 *
 * 池的写法: 能者多劳。
 *
 * 但是当前这个版本是有盲等的。可以通过条件变量来解决。
 */
int main() {


    pthread_t tid[THR_NUM];

    for (int i = 0; i < THR_NUM; ++i) {
//        int err = pthread_create(tid + i, nullptr, thr_prime, (void*) i);
        // TODO 注意: 真正正确的改进。
        int* pInt = new int(i);
        int err = pthread_create(tid + i, nullptr, thr_prime, pInt);

        /*
        // TODO 注意: 大括号的内容是没有重构前的内容, 这里没有删除而是注释掉。
        {
            // TODO 注意: 这里产生竞争的原因是: 201个指针指向了同一个地址。 &i。
//        int err = pthread_create(tid + (i - LEFT), nullptr, thr_prime, &i);
            // TODO 注意: 改进
            //  这个改进依然是错误的。
            int err = pthread_create(tid + (i - LEFT), nullptr,
                                     thr_prime, (void*) i);
//        int tmp = i;
//        int err = pthread_create(tid + (i - LEFT), nullptr, thr_prime, &tmp);
        }
        */

        if (err) {
            std::fprintf(stderr, "pthread_create(): %s\n", std::strerror(err));
            std::exit(1);
        }
    }


    // 下发任务的环节
    for (int i = LEFT; i <= RIGHT; ++i) {
        pthread_mutex_lock(&mutexNum);
        while (num != 0) {
            pthread_mutex_unlock(&mutexNum);
            // TODO 注意: sched_yield()函数是出让调度器给其它线程。
            sched_yield();
            // TODO 注意: 程序中尽量不要出现 sleep()函数调用。
//            sleep(1);
            pthread_mutex_lock(&mutexNum);
        }
        num = i;
        pthread_mutex_unlock(&mutexNum);
    }

    pthread_mutex_lock(&mutexNum);
    while (num != 0) {
        pthread_mutex_unlock(&mutexNum);
        sched_yield();
        pthread_mutex_lock(&mutexNum);
    }
    num = -1;
    pthread_mutex_unlock(&mutexNum);


    for (int i = 0; i < THR_NUM; ++i) {
        pthread_join(tid[i], nullptr);
    }


    pthread_mutex_destroy(&mutexNum);

    std::exit(EXIT_SUCCESS);
}

static void* thr_prime(void* pVoid) {
    int tid = *((int*) pVoid);
    delete (int*) pVoid;

    while (true) {
        pthread_mutex_lock(&mutexNum);
        while (num == 0) {
            pthread_mutex_unlock(&mutexNum);
            sched_yield();
            pthread_mutex_lock(&mutexNum);
        }
        // TODO 注意: 要注意所以临界区的代码跳转！！！！
        //  break
        //  continue
        //  invoke function
        //  goto
        //  jmp
        //  防止死锁。
        if (num == -1) {
            pthread_mutex_unlock(&mutexNum);
            break;
        }
        int i = num;
        num = 0;
        pthread_mutex_unlock(&mutexNum);

        int mark{1};
        for (int j = 2; j < i / 2; ++j) {
            if (i % j == 0) {
                mark = 0;
                break;
            }
        }
        if (mark == 1) {
            std::fprintf(stdout, "[%d]%d is prime number.\n", tid, i);
        }
        // TODO 注意: 不要放在这里(while循环内)。
//        delete (int*) pVoid;
    }


//    sleep(100);

    pthread_exit(nullptr);
}